﻿using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.Logger;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Services.AppointAPI;
using AJWPFAdmin.Services.EF;
using Dapper;
using DocumentFormat.OpenXml.Spreadsheet;
using MaterialDesignThemes.Wpf;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Prism.Ioc;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AJWPFAdmin.Services.Jobs
{
    public class QinYouGoodsInfoProcessJob : IAJJob
    {
        public class QinYouGoodsInfoModel
        {
            public string MATCHID { get; set; }
            public DateTime? suttletime { get; set; }
            public string CARNO { get; set; }
            public string MATERIALNAME { get; set; }
            public decimal suttle { get; set; }
            public string SOURCENAME { get; set; }
            public string TARGETNAME { get; set; }
            public DateTime? grosstime { get; set; }
            public DateTime? taretime { get; set; }
        }

        public class QinYouGoodsInfoProcessQuarztJob : IJob
        {
            private static readonly List<(string ip, string name)> _dataBaseList = new()
            {
                ("192.168.200.2","jldb2"),
                ("192.168.200.4","jldb1"),
                ("192.168.200.4","jldb2"),
                ("192.168.200.4","xsdb"),
                ("192.168.200.4","xsdb1"),
                ("192.168.200.134","jldb1"),
                ("192.168.200.134","jldb2"),
                ("192.168.200.213","jldb"),
                ("192.168.200.136","jldb1"),
                ("192.168.200.136","jldb2"),
            };

            private static readonly string _jzDateField = nameof(QinYouGoodsInfoModel.suttletime);
            private static readonly string _carNoField = nameof(QinYouGoodsInfoModel.CARNO);

            private static AJLog4NetLogger _logger;

            public async Task Execute(IJobExecutionContext context)
            {
                context.MergedJobDataMap.TryGetValue("container", out var container);
                if (container is not IContainerProvider provider)
                {
                    return;
                }

                _logger ??= provider.Resolve<AJLog4NetLogger>();

                try
                {
                    using var db = DbService.GetDbContext(provider.Resolve<AJConfigService>());

                    var appointSvc = provider.Resolve<AppointAPISvc>();

                    var goodsSource = db.Goods.AsNoTracking().ToList();

                    var emptyGoods = "空车";

                    var now = DateTime.Now;

                    var carType = (long)CarTypeEnum.进出厂车;

                    var records = await db.ShippingRecords
                        .Where(p => (string.IsNullOrWhiteSpace(p.OutGoodsName)
                        || p.OutGoodsName == emptyGoods)
                        && p.ShipStartDate != null && p.ShipEndDate != null
                        && p.TypeId == carType).ToListAsync();

                    if (records.Count == 0)
                    {
                        _logger.Debug($"秦邮物资匹配定时器:没有记录数据待匹配");
                        return;
                    }

                    _logger.Debug($"秦邮物资匹配定时器:以下车牌号进入匹配:{string.Join(",", records.Select(p => p.CarNo))}");

                    var dbOptionBuilder = new SqlConnectionStringBuilder
                    {
                        //DataSource = apiConfig.DbServer,
                        UserID = "measure_user",
                        Password = "qydb123",
                        TrustServerCertificate = true,
                        MultipleActiveResultSets = true,
                    };

                    var updated = 0;

                    foreach (var record in records)
                    {
                        var result = await ProcessSingleAsync(db, appointSvc,
                            record, dbOptionBuilder,
                            goodsSource);
                        if (!result.Success)
                        {
                            _logger.Debug($"秦邮物资匹配定时器:{result.Message},继续下一条数据");
                            continue;
                        }
                        var recordProcess = result.Data as ShippingRecord;
                        db.Entry(recordProcess).State = EntityState.Modified;
                        updated++;
                    }

                    if (updated > 0)
                    {
                        await db.SaveChangesAsync();
                    }

                    _logger.Debug($"秦邮物资匹配定时器:任务完成:共{records.Count} 已更新:{updated}");
                }
                catch (Exception e)
                {
                    _logger.Error($"秦邮物资匹配定时器:处理逻辑异常:{e.Message}", e);
                }

            }

            public static async Task<ProcessResult> ProcessSingleAsync(DbService db,
                AppointAPISvc appointAPISvc,
                ShippingRecord record,
                SqlConnectionStringBuilder dbOptionBuilder = null,
                List<Goods> goodsSource = null)
            {
                dbOptionBuilder ??= new SqlConnectionStringBuilder
                {
                    //DataSource = apiConfig.DbServer,
                    UserID = "measure_user",
                    Password = "qydb123",
                    TrustServerCertificate = true,
                    MultipleActiveResultSets = true,
                };

                var result = await ProcessAsync(record, dbOptionBuilder);

                if (result.Data is not QinYouGoodsInfoModel model)
                {
                    result.SetError($"{record.CarNo} 未查询到数据");
                    return result;
                }

                goodsSource ??= db.Goods.AsNoTracking().ToList();

                var goodsName = model.MATERIALNAME;

                var goodsItem = goodsSource.FirstOrDefault(p => p.Name == goodsName);

                record.OutGoodsName = goodsName;
                record.OutGoodsType = goodsItem?.Category ?? record.OutGoodsType;
                record.OutGoodsIsBulkCargo = goodsItem?.IsBulkCargo ?? record.OutGoodsIsBulkCargo;
                record.OutGoodsVolume = model.suttle;
                record.Sender = model.SOURCENAME;
                record.Receiver = model.TARGETNAME;
                record.UpdateDate = DateTime.Now;

                // 上传台账
                if (appointAPISvc != null && appointAPISvc.API is QinYouAppointAPI qinyouApi)
                {
                    var uploadResult = await qinyouApi.CustomUploadShippingRecordAsync(new ShippingRecordParams
                    {
                        Record = record
                    }, model);

                    _logger.Debug($"秦邮台账数据库直写结果:{result.Message}");
                }

                result.SetSuccess(record);

                return result;

            }

            private static async Task<ProcessResult> ProcessAsync(ShippingRecord record, SqlConnectionStringBuilder dbOptionBuilder)
            {
                var result = new ProcessResult();

                QinYouGoodsInfoModel model = null;

                if (record.TypeId != (long)CarTypeEnum.进出厂车)
                {
                    result.SetSuccess(model);
                    return result;
                }

                var carNo = record.CarNo;
                var start = record.ShipStartDate.GetValueOrDefault().ToCommonDateString();
                var end = record.ShipEndDate.GetValueOrDefault().ToCommonDateString();

                foreach (var dbCfg in _dataBaseList)
                {
                    dbOptionBuilder.DataSource = dbCfg.ip;
                    dbOptionBuilder.InitialCatalog = dbCfg.name;
                    var builder = new DbContextOptionsBuilder<DbService>();
                    builder.UseSqlServer(dbOptionBuilder.ConnectionString, bd =>
                    {
                        bd.CommandTimeout(15);
                        bd.EnableRetryOnFailure(3);
                    });

                    try
                    {
                        using var mssqlDb = new DbService(builder.Options);

                        var conn = mssqlDb.Database.GetDbConnection();

                        var sql = $"select * from Measure_View where {_jzDateField} > @start and {_jzDateField} < @end and {_carNoField} = @carNo order by {_jzDateField} desc";

                        _logger.Debug($"秦邮物资匹配定时器:数据源:{dbCfg.ip};数据库:{dbCfg.name}\r\n查询sql:{sql}\r\n参数:start:{start};end:{end};carNo:{carNo}\r\n");

                        model = await conn.QueryFirstOrDefaultAsync<QinYouGoodsInfoModel>(sql, new
                        {
                            start,
                            end,
                            carNo
                        });

                        if (model != null)
                        {
                            _logger.Debug($"秦邮物资匹配定时器:匹配到数据{CommonUtil.AJSerializeObject(model)}\r\n");
                            break;
                        }
                    }
                    catch (Exception ee)
                    {
                        _logger.Error($"秦邮物资匹配定时器:carNo:{carNo} 查询异常:{ee.Message}", ee);
                        continue;
                    }
                }

                result.SetSuccess(model);

                return result;
            }
        }

        public void Init(IContainerProvider container, IScheduler scheduler)
        {
            var jobData = new Dictionary<string, object> { { "container", container } };
            var map = new JobDataMap
            {
                { "container", container }
            };
            var key = nameof(QinYouGoodsInfoProcessJob);
            var job = JobBuilder.Create<QinYouGoodsInfoProcessQuarztJob>().WithIdentity(key)
                .SetJobData(map)
                .WithDescription("秦邮物资查询匹配定时器").Build();

            var trigger = TriggerBuilder.Create().WithIdentity(key).WithCronSchedule("0 0/1 * 1/1 * ? *").Build();
            //var trigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule((b) =>
            //{
            //    b.WithIntervalInSeconds(10);
            //}).Build();

            scheduler.ScheduleJob(job, trigger);
        }
    }
}
